/*
 * onvif configuration file design:
 * 		## Class Config ##
 * 		@total=10
 * 		@token1
 * 		{
 * 			...;//name
 * 			...;//token
 * 			...;//usecount
 * 			...
 * 		}
 * 		@token2
 * 		{
 * 			...;
 * 			...;
 * 			...
 * 		}
 * 		## Class2 Config ##
 * 		@total=10
 * 		@token1
 * 		{
 * 			...
 * 		}
 * 		@token2
 * 		{
 * 			...
 * 		}
 *
 * check special flags: class-flag '#', id-flag '@'
 * 1.insert config:
 * 	@1.find whether class config exists or not 
 * 	@2.if yes,insert current config and update '@total' value
 * 	@3.if no, create class config and insert '@total' info, and current config
 *
 * 2.get config:
 * 	@1.find class config that need to get
 * 	@2.find '@token' value that equals to current token if has.
 * 	@3.read configuration information from file.
 *
 * 3.update config:
 * 	@1.find class config that need to update
 * 	@2.find '@token' value that equals to current token
 * 	@3.get and update configuration params
 * 	@4.save modified configuration params to file
 *
 */

#include "soapH.h"
#include "onvif.h"

#define LINE_LEN 512
static char line[LINE_LEN]={0};
static char *remain_lines = NULL; //save remain file content,heap pointer
static char *inter_lines = NULL; //save internal lines in delete operation.

/*
 * get configurations interfaces
 */
static long get_class_fpos(FILE *file, const char *config_name)
{
	if(file == NULL || config_name == NULL)
	{
		DBG("invalid params!\n");
		return -1;
	}

	clearerr(file);
	fseek(file,0,SEEK_SET);
	while(fgets(line,LINE_LEN,file) != NULL)
	{
		if(line[0]=='#'&&line[1]=='#'&&strstr(line,config_name)!=NULL)
			break;
	}

	return ftell(file);
}

static long get_token_fpos(FILE *file, long offset, const char *token_name)
{
	long token_fpos;

	fseek(file,offset,SEEK_SET);
	while(fgets(line,LINE_LEN,file) != NULL)
	{
		if(line[0]=='@'&&strstr(line,token_name)!=NULL)
		{
			token_fpos = ftell(file);
			break;
		}
		if(line[0]=='#')
		{
			token_fpos = -1;
			fseek(file,offset,SEEK_SET);
			break;
		}
	}

	return token_fpos;
}

static int backup_next(FILE *file, char **buff, long size)
{
	*buff = (char *)malloc(size);

	memset(*buff,0,size);
	clearerr(file);
	fread(*buff, size, 1, file);

	if(ferror(file))
		return -1;
	else
		return 0;
}

static int restore_next(FILE *file,char **buff,long size)
{
	//clearerr(file);
	if(*buff)
	{
		fwrite(*buff,size,1,file);
		free(*buff);
		*buff = NULL;
	}
	else
		return -1; 

	if(ferror(file))
		return -1;
	else
		return 0;
}

static int save_config(FILE *file,void *config, CONFIG_SAVE_TYPE type)
{
	fwrite("{\n", 2, 1, file);

	const char *pnull = "NULL";
	char *pstr = NULL;
	struct tt__Profile *pprofile = NULL;
	struct tt__VideoSourceConfiguration *pvs = NULL;
	struct tt__VideoOutputConfiguration *pvo = NULL;
	struct tt__AudioSourceConfiguration *pas = NULL;
	struct tt__AudioOutputConfiguration *pao = NULL;
	struct tt__VideoEncoderConfiguration *pve = NULL;  
	struct tt__AudioEncoderConfiguration *pae = NULL;  
	struct tt__AudioDecoderConfiguration *padec = NULL;  
	
	struct _tds__SetDNS *pdns = NULL;
	struct _tds__SetNTP *pntp = NULL;
	struct _tds__SetDynamicDNS *pddns = NULL;
//	struct _tds__SetNetworkInterfaces *pni = NULL;
	switch(type)
	{
		case TYPE_VS:
			pvs = (struct tt__VideoSourceConfiguration *)config;
			snprintf(line,LINE_LEN,"\t%s;\t//name\n",pvs->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//usecount\n",pvs->UseCount);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//token\n",pvs->token);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//source token\n",pvs->SourceToken);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d,%d,%d,%d;\t//bounds range\n",
					pvs->Bounds->x, pvs->Bounds->y,pvs->Bounds->width,pvs->Bounds->height);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//any size\n",pvs->__size);
			fwrite(line,strlen(line),1,file);
			if(pvs->__any)
			{
				snprintf(line,LINE_LEN,"\t%s;\t//any\n",pvs->__any);
				fwrite(line,strlen(line),1,file);
			}
			if(pvs->__anyAttribute)
			{
				snprintf(line,LINE_LEN,"\t%s;\t//any attribute\n",pvs->__anyAttribute);
				fwrite(line,strlen(line),1,file);
			}
			break;
		case TYPE_VO:
			pvo = (struct tt__VideoOutputConfiguration *)config;
			snprintf(line,LINE_LEN,"\t%s;\t//name\n",pvo->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//usecount\n",pvo->UseCount);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//token\n",pvo->token);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//output token\n",pvo->OutputToken);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//any size\n",pvo->__size);
			fwrite(line,strlen(line),1,file);
			break;
		case TYPE_AS:
			pas = (struct tt__AudioSourceConfiguration *)config;
			snprintf(line,LINE_LEN,"\t%s;\t//name\n",pas->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//usecount\n",pas->UseCount);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//token\n",pas->token);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//source token\n",pas->SourceToken);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//any size\n",pas->__size);
			fwrite(line,strlen(line),1,file);
			break;
		case TYPE_AO:
			pao = (struct tt__AudioOutputConfiguration *)config;
			snprintf(line,LINE_LEN,"\t%s;\t//name\n",pao->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//usecount\n",pao->UseCount);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//token\n",pao->token);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//output token\n",pao->OutputToken);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//send primacy\n",pao->SendPrimacy);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//output level\n",pao->OutputLevel);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//any size\n",pao->__size);
			fwrite(line,strlen(line),1,file);
			break;
		case TYPE_VE:
			pve = (struct tt__VideoEncoderConfiguration*)config;
			snprintf(line,LINE_LEN,"\t%s;\t//name\n",pve->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//usecount\n",pve->UseCount);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//token\n",pve->token);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//encodeing, JPEG=0,MPEG4=1,H264=2\n",pve->Encoding);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;%d;\t//resolution:width;height;\n",pve->Resolution->Width,pve->Resolution->Height);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%f;\t//quality, 1-10\n",pve->Quality);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;%d;%d;\t//video rate control\n",pve->RateControl->FrameRateLimit,
					pve->RateControl->EncodingInterval,pve->RateControl->BitrateLimit);
			fwrite(line,strlen(line),1,file);
			if(pve->MPEG4 != NULL)
			{
				snprintf(line,LINE_LEN,"\t%d;%d;\t//mpeg4 configuration: govlength;profile:sp=0,asp=1\n",
						pve->MPEG4->GovLength,pve->MPEG4->Mpeg4Profile);
				fwrite(line,strlen(line),1,file);
			}
			else 
			{
				snprintf(line,LINE_LEN,"\t;\t//mpeg4 configuration\n");
				fwrite(line,strlen(line),1,file);
			}
			if(pve->H264 != NULL)
			{
				snprintf(line,LINE_LEN, "\t%d;%d;\t//h264 configuration:govlength;profile:baseline=0,main=1,extended=2,high=3\n",
						pve->H264->GovLength,pve->H264->H264Profile);
				fwrite(line,strlen(line),1,file);
			}
			else 
			{
				snprintf(line,LINE_LEN,"\t;\t//h264 configuration\n");
				fwrite(line,strlen(line),1,file);
			}
			snprintf(line,LINE_LEN,"\t%s,%s;%d;%d;%s;%d;\t//multicast configuration: ip;port;ttl;autostart;__size;\n",
					pve->Multicast->Address->Type?"ipv6":"ipv4",pve->Multicast->Address->IPv4Address,
					pve->Multicast->Port,pve->Multicast->TTL,pve->Multicast->AutoStart?"true":"false",
					pve->Multicast->__size);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%ld;\t//session timeout,unit:ms\n", pve->SessionTimeout);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//any size\n",pve->__size);
			fwrite(line,strlen(line),1,file);
			break;
		case TYPE_AE:
			pae = (struct tt__AudioEncoderConfiguration*)config;
			snprintf(line,LINE_LEN,"\t%s;\t//name\n",pae->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//usecount\n",pae->UseCount);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//token\n",pae->token);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//audio encoding:G711 - 0,G726 - 1,AAc - 3\n",pae->Encoding);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//bitrate,unit:kbps\n",pae->Bitrate);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//samplerate,unit:kHz\n",pae->SampleRate);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s,%s;%d;%d;%s;%d;\t//multicast configuration: ip;port;ttl;autostart;__size;\n",
					pae->Multicast->Address->Type?"ipv6":"ipv4",pae->Multicast->Address->IPv4Address,
					pae->Multicast->Port,pae->Multicast->TTL,pae->Multicast->AutoStart?"true":"false",
					pae->Multicast->__size);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%ld;\t//session timeout,unit:ms\n", pae->SessionTimeout);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//any size\n",pae->__size);
			fwrite(line,strlen(line),1,file);
			break;

		case TYPE_ADEC:
			padec = (struct tt__AudioDecoderConfiguration *)config;
			snprintf(line,LINE_LEN,"\t%s;\t//name\n",padec->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//usecount\n",padec->UseCount);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//token\n",padec->token);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//any size\n",padec->__size);
			fwrite(line,strlen(line),1,file);
			break;


		case TYPE_STR:
			pstr = (char *)config;
			snprintf(line,LINE_LEN, "\t%s;\t\n", pstr);
			fwrite(line,strlen(line),1,file);
			break;

		case TYPE_DNS:
			pdns =(struct _tds__SetDNS*)config;
			snprintf(line,LINE_LEN,"\t%d;\t//FromDHCP\n",pdns->FromDHCP);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//size SearchDomain\n",pdns->__sizeSearchDomain);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//SearchDomain\n",pdns->SearchDomain);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//size DNS Manual\n",pdns->__sizeDNSManual);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d,%s,%s;\t//DNS Manual\n",
					pdns->DNSManual->Type,pdns->DNSManual->IPv4Address,pdns->DNSManual->IPv6Address);
			fwrite(line,strlen(line),1,file);
			break;

		case TYPE_NTP:
			pntp = (struct _tds__SetNTP *)config;
			snprintf(line,LINE_LEN,"\t%d;\t//FromDHCP\n",pntp->FromDHCP);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d;\t//size NTPManual\n",pntp->__sizeNTPManual);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%d,%s,%s,%s,%s,%s;\t//NTPManual\n",
					pntp->NTPManual->Type,pntp->NTPManual->IPv4Address,pntp->NTPManual->IPv6Address,
					pntp->NTPManual->DNSname,pntp->NTPManual->Extension,pntp->NTPManual->__anyAttribute);
			fwrite(line,strlen(line),1,file);
			break;
		case TYPE_DDNS:
			pddns =(struct _tds__SetDynamicDNS *)config;
			snprintf(line,LINE_LEN,"\t%d;\t//TYPE\n",pddns->Type);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//NAME\n",pddns->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//TTL\n",pddns->TTL);
			fwrite(line,strlen(line),1,file);
		
			break;
#if 0
		case TYPE_NETFACE:
            pni =(struct _tds__SetNetworkInterfaces *)config;
			snprintf(line,LINE_LEN,"\t%d;\t//TYPE\n",pni->Type);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//NAME\n",pni->Name);
			fwrite(line,strlen(line),1,file);
			snprintf(line,LINE_LEN,"\t%s;\t//TTL\n",pni->TTL);
			fwrite(line,strlen(line),1,file);
			
			break;
#endif
		case TYPE_PROFILE:
			pprofile = (struct tt__Profile *)config;
			snprintf(line,LINE_LEN,"\t%s\t//name\n",pprofile->Name);
			fputs(line,file);
			snprintf(line,LINE_LEN,"\t%s\t//token\n",pprofile->token);
			fputs(line,file);
			snprintf(line,LINE_LEN,"\t%s\t//fixed\n",*pprofile->fixed?"true":"false");
			fputs(line,file);
			if(pprofile->VideoSourceConfiguration != NULL)
			{
				snprintf(line,LINE_LEN,"\t%s\t//video source token\n",pprofile->VideoSourceConfiguration->token);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t//video source token\n",pnull);
			}
			fputs(line,file);
			if(pprofile->AudioSourceConfiguration != NULL)
			{
				snprintf(line,LINE_LEN,"\t%s\t//audio source token\n",pprofile->AudioSourceConfiguration->token);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
			}
			fputs(line,file);
			if(pprofile->VideoEncoderConfiguration != NULL)
			{
				snprintf(line,LINE_LEN,"\t%s\t//video encoder\n",pprofile->VideoEncoderConfiguration->token);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
			}
			fputs(line,file);
			if(pprofile->AudioEncoderConfiguration != NULL)
			{
				snprintf(line,LINE_LEN,"\t%s\t//audio encoder\n",pprofile->AudioEncoderConfiguration->token);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
			}
			fputs(line,file);
			if(pprofile->VideoAnalyticsConfiguration != NULL)
			{
				snprintf(line,LINE_LEN,"\t%s\t//video analytics token\n",pprofile->VideoAnalyticsConfiguration->token);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
			}
			fputs(line,file);
			if(pprofile->PTZConfiguration != NULL)
			{
				snprintf(line,LINE_LEN,"\t%s\t//ptz token\n",pprofile->PTZConfiguration->token);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
			}
			fputs(line,file);
			if(pprofile->MetadataConfiguration != NULL)
			{
				snprintf(line,LINE_LEN,"\t%s\t//meta token\n",pprofile->MetadataConfiguration->token);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
			}
			fputs(line,file);
			if(pprofile->Extension != NULL)
			{
				if(pprofile->Extension->AudioOutputConfiguration != NULL)
				{
					snprintf(line,LINE_LEN,"\t%s\t//audio output token\n",pprofile->Extension->AudioOutputConfiguration->token);
				}
				else
				{
					snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
				}
				fputs(line,file);
				if(pprofile->Extension->AudioDecoderConfiguration != NULL)
				{
					snprintf(line,LINE_LEN,"\t%s\t//audio decoder token\n",pprofile->Extension->AudioDecoderConfiguration->token);
				}
				else
				{
					snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
				}
				fputs(line,file);
			}
			else
			{
				snprintf(line,LINE_LEN,"\t%s\t\n",pnull);
				fputs(line,file);
				fputs(line,file);
			}
			break;

		default:
			break;
	}

	fwrite("}\n",2, 1, file);
	
	return 0;
}

static int save_config_byarray(FILE *file,char *array[], int num)
{
	int i;

	fwrite("{\n", 2, 1, file);
	for(i=0;i<num;i++)
	{
		if(array[i]!=NULL)
		{
			snprintf(line,LINE_LEN,"\t%s\n",array[i]);
			fwrite(line,strlen(line),1,file);
		}
		else
		{
			snprintf(line,LINE_LEN,"\tNULL\n");
			fwrite(line,strlen(line),1,file);
		}
	}
	fwrite("}\n",2, 1, file);
	
	return 0;
}

int free_config_space(char *config[], int size)
{
	if(config == NULL) return 0;
	int i;
	for(i=0;i<size;i++)
	{
		if(config[i]!=NULL)
		{
			free(config[i]);
			config[i] = NULL;
		}
	}

	return 0;
}

static int get_config(FILE *file,char *config[], int size)
{//inverse operation to save_config
	fgets(line, LINE_LEN, file);
	if(strstr(line,"{")==NULL)
		return -1;

	//read params to config
	int i, len;
	char buff[LINE_LEN]={0};
	for(i=0;i<size;i++)
	{
		fgets(line,LINE_LEN,file);
		if(strstr(line,"NULL")!=NULL)
		{
			config[i] = NULL;
		}
		else
		{
			sscanf(line,"\t%[^\t/\n]", buff);
			len = strlen(buff);
			config[i] = (char *)malloc(len+1);
			if(config[i]==NULL) 
				free_config_space(config,i);
			memcpy(config[i],buff,len+1);
		}
	}

	for(;i<size;i++)
		config[i] = NULL;

	while(fgets(line,LINE_LEN,file)!=NULL)
	{
		if(strstr(line,"}")!=NULL)
			break;
	}

	return 0;
}

static int query_config(FILE *stream, const char *name, const char *token, char *config[], int size)
{
	long class_fpos, token_fpos;

	class_fpos = get_class_fpos(stream,name);

	if(feof(stream))
	{//there is no the class,error
		clearerr(stream);
		DBG("the config class doesnot exist!\n");
		return -1;
	}
	if(class_fpos > 0)
	{//class header exists,search config token
		token_fpos = get_token_fpos(stream,class_fpos,token);
		if(token_fpos > 0) // --> "{"
		{
			get_config(stream,config,size);
		}
		else
		{
			DBG("token is invalid!\n");
			return -1;
		}
	}
	return 0;
}

static int query_all_config(FILE *stream, const char *name, char *configs[], int set_size, int *config_num, int elem_size)
{
	long class_fpos;
	int i;

	class_fpos = get_class_fpos(stream,name);

	if(feof(stream))
	{//there is no the class,error
		clearerr(stream);
		DBG("the config class doesnot exist!\n");
		return -1;
	}
	else if(class_fpos > 0)
	{//class header exists
		fgets(line,LINE_LEN,stream);
		sscanf(line,"@total=%d",config_num);
		if(*config_num > set_size)
			return -1;
		for(i=0;i<*config_num;i++)
		{
			fgets(line,LINE_LEN,stream);
			if(strstr(line,"@")!=NULL)
			{
				get_config(stream,configs+i*elem_size,elem_size);
			}
		}
	}

	return 0;
}

static int update_config(FILE *stream, const char *name,const char *token, void *config, CONFIG_SAVE_TYPE type)
{
	if(name==NULL||config == NULL ||type >= TYPE_MAX)
	{
		DBG("invalid params!\n");
		return -1;
	}

	long class_fpos,end_fpos,token_fpos,next_fpos;
	long size;

	fseek(stream,0,SEEK_END);
	end_fpos = ftell(stream);
	rewind(stream);
	class_fpos = get_class_fpos(stream,name);
	if(class_fpos == end_fpos)
	{//there is no the class,error
		DBG("the config class doesnot exist!\n");
		return -1;
	}
	else if(class_fpos > 0)
	{//class header exists,search config token
		token_fpos = get_token_fpos(stream,class_fpos,token);
		if(token_fpos > 0)
		{
			while(fgets(line,LINE_LEN,stream)!=NULL)
			{
				if(strstr(line,"}")!=NULL)
					break;
			}
			next_fpos = ftell(stream);
			size = end_fpos - next_fpos;
			backup_next(stream,&remain_lines,size);
			fseek(stream,token_fpos,SEEK_SET);
			save_config(stream,config,type);
			restore_next(stream,&remain_lines,size);

			fflush(stream);
			ftruncate(fileno(stream), ftell(stream));
		}
		else
		{
			DBG("token is invalid!\n");
			return -1;
		}
	}

	return 0;
}

static int update_config_byarray(FILE *stream, const char *name,const char *token, char *array[], int num)
{
	if(name==NULL||token == NULL ||array== NULL)
	{
		DBG("invalid params!\n");
		return -1;
	}

	long class_fpos,end_fpos,token_fpos,next_fpos;
	long size;

	fseek(stream,0,SEEK_END);
	end_fpos = ftell(stream);
	rewind(stream);
	class_fpos = get_class_fpos(stream,name);
	if(class_fpos == end_fpos)
	{//there is no the class,error
		DBG("the config class doesnot exist!\n");
		return -1;
	}
	else if(class_fpos > 0)
	{//class header exists,search config token
		token_fpos = get_token_fpos(stream,class_fpos,token);
		if(token_fpos > 0)
		{
			while(fgets(line,LINE_LEN,stream)!=NULL)
			{
				if(strstr(line,"}")!=NULL)
					break;
			}
			next_fpos = ftell(stream);
			size = end_fpos - next_fpos;
			backup_next(stream,&remain_lines,size);
			fseek(stream,token_fpos,SEEK_SET);
			save_config_byarray(stream,array,num);
			restore_next(stream,&remain_lines,size);

			fflush(stream);
			ftruncate(fileno(stream), ftell(stream));
		}
		else
		{
			DBG("token [%s] is invalid!\n", token);
			return -1;
		}
	}

	return 0;
}
static int insert_config(FILE *stream, const char *name,const char *token, void *config, CONFIG_SAVE_TYPE type)
{
	if(name==NULL||config == NULL ||type >= TYPE_MAX)
	{
		DBG("invalid params!\n");
		return -1;
	}

	long class_fpos,end_fpos,next_fpos,size;
	int config_num = 0;

	fseek(stream,0,SEEK_END);
	end_fpos = ftell(stream);
	rewind(stream);
	class_fpos = get_class_fpos(stream,name);
	if(class_fpos == end_fpos)
	{//there is no the class,so create class header
		snprintf(line,LINE_LEN,"## %s ##\n",name);
		fwrite(line, strlen(line),1,stream);
		config_num = 1;
		snprintf(line,LINE_LEN,"@total=%d\n",config_num);
		fwrite(line, strlen(line),1,stream);
		snprintf(line,LINE_LEN,"@%s\n",token);
		fwrite(line, strlen(line),1,stream);
		save_config(stream,config,type);
	}
	else if(class_fpos > 0 && get_token_fpos(stream,class_fpos,token) > 0)
	{//class header exists and token exists
		return -1;
	}
	else
	{
		fgets(line,LINE_LEN,stream);
		sscanf(line,"@total=%d",&config_num);
		config_num += 1;

		next_fpos = ftell(stream);
		size = end_fpos - next_fpos;
		backup_next(stream,&remain_lines,size);
		fseek(stream,class_fpos,SEEK_SET);
		snprintf(line,LINE_LEN,"@total=%d\n",config_num);
		fwrite(line, strlen(line),1,stream);
		snprintf(line,LINE_LEN,"@%s\n",token);
		fwrite(line, strlen(line),1,stream);
		save_config(stream,config,type);
		restore_next(stream,&remain_lines,size);
	}

	return 0;
}

static int insert_config_byarray(FILE *stream, const char *name,const char *token, char *array[], int num)
{
	if(name==NULL||token == NULL )
	{
		DBG("invalid params!\n");
		return -1;
	}

	long class_fpos,end_fpos,next_fpos,size;
	int config_num = 0;

	fseek(stream,0,SEEK_END);
	end_fpos = ftell(stream);
	rewind(stream);
	class_fpos = get_class_fpos(stream,name);
	if(class_fpos == end_fpos)
	{//there is no the class,so create class header
		snprintf(line,LINE_LEN,"## %s ##\n",name);
		fwrite(line, strlen(line),1,stream);
		config_num = 1;
		snprintf(line,LINE_LEN,"@total=%d\n",config_num);
		fwrite(line, strlen(line),1,stream);
		snprintf(line,LINE_LEN,"@%s\n",token);
		fwrite(line, strlen(line),1,stream);
		save_config_byarray(stream,array,num);
	}
	else if(class_fpos > 0 && get_token_fpos(stream,class_fpos,token) > 0)
	{//class header exists and token exists
		return -1;
	}
	else
	{
		fgets(line,LINE_LEN,stream);
		sscanf(line,"@total=%d",&config_num);
		config_num += 1;

		next_fpos = ftell(stream);
		size = end_fpos - next_fpos;
		backup_next(stream,&remain_lines,size);
		fseek(stream,class_fpos,SEEK_SET);
		snprintf(line,LINE_LEN,"@total=%d\n",config_num);
		fwrite(line, strlen(line),1,stream);
		snprintf(line,LINE_LEN,"@%s\n",token);
		fwrite(line, strlen(line),1,stream);
		save_config_byarray(stream,array,num);
		restore_next(stream,&remain_lines,size);
	}

	return 0;
}
static int delete_config(FILE *stream, const char *name,const char *token)
{
	if(name==NULL||token == NULL)
	{
		DBG("invalid params!\n");
		return -1;
	}

	long class_fpos,end_fpos,token_fpos,next_fpos;
	long size,inter_size;
	int config_num = 0;

	fseek(stream,0,SEEK_END);
	end_fpos = ftell(stream);
	rewind(stream);
	class_fpos = get_class_fpos(stream,name);
	if(class_fpos == end_fpos)
	{//there is no the class,error
		DBG("the config class doesnot exist!\n");
		return -1;
	}
	else if(class_fpos > 0)
	{//class header exists,search config token
		fgets(line,LINE_LEN,stream);
		sscanf(line,"@total=%d",&config_num);

		token_fpos = get_token_fpos(stream,class_fpos,token);
		if(token_fpos > 0)
		{
			config_num -= 1;
			while(fgets(line,LINE_LEN,stream)!=NULL)
			{
				if(strstr(line,"}")!=NULL)
					break;
			}
			next_fpos = ftell(stream);
			size = end_fpos - next_fpos;
			backup_next(stream,&remain_lines,size);

			fseek(stream,token_fpos-(strlen(token)+2),SEEK_SET);//--> @'token'\n
			end_fpos = ftell(stream); //internal lines end position
			fseek(stream,class_fpos,SEEK_SET);
			fgets(line,LINE_LEN,stream);
			next_fpos = ftell(stream); //internal lines start position
			inter_size = end_fpos - next_fpos;
			backup_next(stream,&inter_lines, inter_size);

			fseek(stream,class_fpos,SEEK_SET);
			snprintf(line,LINE_LEN,"@total=%d\n",config_num);
			fwrite(line, strlen(line),1,stream);

			restore_next(stream,&inter_lines, inter_size);
			restore_next(stream,&remain_lines, size);

			fflush(stream);
			ftruncate(fileno(stream), ftell(stream));
		}
		else
		{
			DBG("token is invalid!\n");
			return -1;
		}
	}
	return 0;
}

int save_configs(const char *name, void *config, CONFIG_SAVE_TYPE type)
{
	if(name == NULL || config == NULL || type >= TYPE_MAX)
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;
	char token[TOKEN_LEN]={0};
	static int i = 1;
	snprintf(token,TOKEN_LEN,"token_%02d",i++);

	if(access(DEFAULT_CONFIG_FILE, F_OK))
	{
		fd = open(DEFAULT_CONFIG_FILE, O_CREAT|O_RDWR,0777);
	}
	else if(!access(DEFAULT_CONFIG_FILE, W_OK))
	{
		fd = open(DEFAULT_CONFIG_FILE, O_RDWR);
	}
	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	//save_file_configs(fd, name,config,type);
	FILE *stream = fdopen(fd, "r+");
	insert_config(stream,name,token,config,type);

	fclose(stream);
	close(fd);

	return 0;
}


int insert_config_default(const char *name,const char *token, void *config, CONFIG_SAVE_TYPE type)
{
	if(name == NULL || config == NULL || type >= TYPE_MAX)
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;

	if(access(DEFAULT_CONFIG_FILE, F_OK))
	{
		fd = open(DEFAULT_CONFIG_FILE, O_CREAT|O_RDWR,0777);
	}
	else if(!access(DEFAULT_CONFIG_FILE, W_OK))
	{
		fd = open(DEFAULT_CONFIG_FILE, O_RDWR);
	}
	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	FILE *stream = fdopen(fd, "r+");
	insert_config(stream,name,token,config,type);

	fclose(stream);
	close(fd);

	return 0;
}
		
int insert_config_default_byarray(const char *name,const char *token, char *array[], int num)
{
	if(name == NULL || array == NULL )
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;

	if(access(DEFAULT_CONFIG_FILE, F_OK))
	{
		fd = open(DEFAULT_CONFIG_FILE, O_CREAT|O_RDWR,0777);
	}
	else if(!access(DEFAULT_CONFIG_FILE, W_OK))
	{
		fd = open(DEFAULT_CONFIG_FILE, O_RDWR);
	}
	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	FILE *stream = fdopen(fd, "r+");
	insert_config_byarray(stream,name,token,array,num);

	fclose(stream);
	close(fd);

	return 0;
}

int update_config_default(const char *name,const char *token,void *config,CONFIG_SAVE_TYPE type)
{
	if(name == NULL || config == NULL || type >= TYPE_MAX)
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;

	fd = open(DEFAULT_CONFIG_FILE, O_RDWR);
	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	FILE *stream = fdopen(fd, "r+");
	update_config(stream,name,token,config,type);

	fclose(stream);
	close(fd);

	return 0;
}

int update_config_default_byarray(const char *name,const char *token,char *array[],int size)
{
	if(name == NULL || array == NULL )
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;

	fd = open(DEFAULT_CONFIG_FILE, O_RDWR);
	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	FILE *stream = fdopen(fd, "r+");
	update_config_byarray(stream,name,token,array,size);

	fclose(stream);
	close(fd);

	return 0;
}

int delete_config_default(const char *name, const char *token)
{
	if(name == NULL || token == NULL)
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;

	fd = open(DEFAULT_CONFIG_FILE, O_RDWR);
	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	FILE *stream = fdopen(fd, "r+");
	delete_config(stream,name,token);

	fclose(stream);
	close(fd);

	return 0;
}

int query_config_default(const char *name,const char *token,char *config[], int size) 
{
	if(name == NULL || config == NULL )
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;

	fd = open(DEFAULT_CONFIG_FILE, O_RDONLY);
	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	FILE *stream = fdopen(fd, "r+");
	query_config(stream,name,token,config,size);

	fclose(stream);
	close(fd);

	return 0;
}

/*
 * params:
 * 	char *configs[] ==> char *configs[3][10],
 * 	so --> set_size = 3, elem_size =10
 */
int query_all_config_default(const char *name, char *configs[], int set_size, int *config_num, int elem_size)
{
	if(name == NULL || configs == NULL || config_num == NULL)
	{
		DBG("invalid params!\n");
		return -1;
	}

	int fd = -1;

	fd = open(DEFAULT_CONFIG_FILE, O_RDONLY);

	if(fd < 0)
	{
		DBG("open %s fail.\n", DEFAULT_CONFIG_FILE);
		return -1;
	}

	FILE *stream = fdopen(fd, "r");
	if(stream == NULL)
	{
		perror("fdopen fail:");
		return -1;
	}
	query_all_config(stream,name,configs,set_size,config_num,elem_size);

	fclose(stream);
	close(fd);

	return 0;
}

int free_all_space(char *configs[], int set_size, int elem_size)
{
	if(configs == NULL) 
		return 0;

	int i;
	
	for(i = 0;i < set_size;i++)
	{
		free_config_space(configs+i*elem_size, elem_size);
	}

	return 0;
}

